#ifndef _IMAGE_FORMAT_H_
#define _IMAGE_FORMAT_H_

#include <stdio.h>
#include <stdint.h>

typedef enum {
    IMAGE_FORMAT_RGB = 0,
    IMAGE_FORMAT_BGR,
    IMAGE_FORMAT_RGBA,
    IMAGE_FORMAT_BGRA,
    IMAGE_FORMAT_ARGB,
    IMAGE_FORMAT_ABGR,
} ImageFormat;

typedef struct {
    uint8_t r;
    uint8_t g;
    uint8_t b;
} ImagePointRGB;

typedef struct {
    uint8_t b;
    uint8_t g;
    uint8_t r;
} ImagePointBGR;

typedef struct {
    uint8_t r;
    uint8_t g;
    uint8_t b;
    uint8_t a;
} ImagePointRGBA;

typedef struct {
    uint8_t b;
    uint8_t g;
    uint8_t r;
    uint8_t a;
} ImagePointBGRA;

typedef struct {
    uint8_t a;
    uint8_t r;
    uint8_t g;
    uint8_t b;
} ImagePointARGB;

typedef struct {
    uint8_t a;
    uint8_t b;
    uint8_t g;
    uint8_t r;
} ImagePointABGR;

typedef union {
    uint8_t *addr;
    uint32_t *addr32;
    ImagePointRGB *rgb;
    ImagePointBGR *bgr;
    ImagePointRGBA *rgba;
    ImagePointBGRA *bgra;
    ImagePointARGB *argb;
    ImagePointABGR *abgr;
} ImageMem;

typedef struct {
    int32_t width;
    int32_t height;
    int32_t pb;
    int32_t size;
    ImageFormat format;
    ImageMem mem;
} ImageInfo;

class Image;
class ImageGrid;

class Image
{
public:
    ~Image();
    Image(); /* 创建大小和内存都为0 */
    Image(int32_t width, int32_t height, ImageFormat format = IMAGE_FORMAT_BGRA, uint8_t* mem = NULL);
    Image(const Image& obj);

    void Resize(int32_t width, int32_t height, ImageFormat format = IMAGE_FORMAT_BGRA, uint8_t* mem = NULL);

    /* 基础参数获取 */
    int32_t Width() const;
    int32_t Height() const;
    int32_t Pb() const; /* 每像素字节数 */
    int32_t Size() const; /* 内存字节数 */
    ImageFormat Format() const;
    ImageMem Mem(int32_t x = 0, int32_t y = 0) const; /* 返回指定位置内存地址 */
    ImageInfo Info() const;

    void ForceSet(uint8_t* addr); /* 强制内存指针修改(特殊场景使用) */

    /* 对image缩放+转换格式后得到新的image(分配新的内存) */
    void Translate(int32_t width, int32_t height, ImageFormat format, Image& retImg);

    /*
    *  清空图像
    *  1. color格式 0x12345678 其中 78蓝色 56绿色 34红色 12透明度(越大越透明)
    *  2. 下面见到的 color 都是这个格式
    */
    void Clear(uint32_t color = 0);
    /* 范围清空 */
    void Clear(uint32_t color, int32_t x, int32_t y, int32_t width, int32_t height);

    /* 像素写: 会考虑透明度叠加效果 */
    void Write(int32_t x, int32_t y, uint32_t color);
    void Write(int32_t x, int32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
    /* plane缩放到width*height后写到image的(x,y)位置 */
    void Write(int32_t x, int32_t y, int32_t width, int32_t height, Image& plane);
    void Write(int32_t x, int32_t y, int32_t width, int32_t height, ImageGrid& plane);

    /* 像素覆盖: Write 会考虑透明度处理,而 Cover 则是直接覆盖 */
    void Cover(int32_t x, int32_t y, uint32_t color);
    void Cover(int32_t x, int32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
    /* plane缩放到width*height后写到image的(x,y)位置 */
    void Cover(int32_t x, int32_t y, int32_t width, int32_t height, Image& plane);
    void Cover(int32_t x, int32_t y, int32_t width, int32_t height, ImageGrid& plane);

private:
    ImageInfo info;
};

/*
 * ImageGrid 共用 Image 的图像内存 
 * ImageGrid 存活期间 Image 不能被 释放 和 Resize
 */
class ImageGrid
{
public:
    ~ImageGrid();
    ImageGrid();

    ImageGrid(Image& image, int32_t divX = 1, int32_t divY = 1); /* 切块模式:用于动画胶片 */
    ImageGrid(Image& image, int32_t x, int32_t y, int32_t width, int32_t height); /* 范围模式:用于区域映射 */
    ImageGrid(ImageGrid& imageGrid, int32_t x, int32_t y, int32_t width, int32_t height);

    /* 基础参数获取 */
    int32_t X() const;
    int32_t Y() const;
    int32_t Width() const;
    int32_t Height() const;
    int32_t Pb() const; /* 每像素字节数 */
    int32_t Size() const; /* 内存字节数 */
    ImageFormat Format() const;
    ImageMem Mem(int32_t x = 0, int32_t y = 0) const; /* 返回指定位置内存地址 */
    ImageInfo ShadowInfo() const; /* 返回原图参数结构 */

    /* ----- 切块模式:用于动画胶片 ----- */

    /* 重新分块(将重置序号为0) */
    void GridResize(int32_t divX = 1, int32_t divY = 1);

    /* 获取序号和分块数 */
    int32_t GridIndex();
    int32_t GridNum();

    /* 设置和移动分块序号 */
    void GridSet(int32_t index);
    ImageMem GridNext();

    /* ----- 范围模式:用于区域映射 ----- */

    /* 设置特定范围模式(宽高优先于xy设置) */
    void RangeSet(int32_t x, int32_t y, int32_t width, int32_t height);

    /* 范围跑动,x,y轴增量式移动(将超出边界时会被限制在边界内) */
    ImageMem RangeMove(int32_t x, int32_t y);

    /* ----- 截取并生成新Image(注意释放内存) ----- */
    Image* ScreenShot();

    /* ----- 同Image ----- */
    void Clear(uint32_t color = 0);
    /* 范围清空 */
    void Clear(uint32_t color, int32_t x, int32_t y, int32_t width, int32_t height);

    /* 像素写: 会考虑透明度叠加效果 */
    void Write(int32_t x, int32_t y, uint32_t color);
    void Write(int32_t x, int32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
    /* plane缩放到width*height后写到image的(x,y)位置 */
    void Write(int32_t x, int32_t y, int32_t width, int32_t height, Image& plane);
    void Write(int32_t x, int32_t y, int32_t width, int32_t height, ImageGrid& plane);

    /* 像素覆盖: Write 会考虑透明度处理,而 Cover 则是直接覆盖 */
    void Cover(int32_t x, int32_t y, uint32_t color);
    void Cover(int32_t x, int32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
    /* plane缩放到width*height后写到image的(x,y)位置 */
    void Cover(int32_t x, int32_t y, int32_t width, int32_t height, Image& plane);
    void Cover(int32_t x, int32_t y, int32_t width, int32_t height, ImageGrid& plane);

private:
    int32_t divX, divY; /* 横纵向分割块数 */
    int32_t width, height; /* 分割后小块的宽高 */
    int32_t index; /* 分割后按从左到右从上到下编排的序号计数(从0数起) */
    int32_t block; /* 分块数 */
    int32_t x, y; /* 范围显示模式的起始坐标 */

    ImageMem mem; /* 起始地址 */
    Image shadow; /* 原图影子 */
};

#endif // _IMAGE_FORMAT_H_
